#include "zookeeperutil.h"
#include "mprpcapplication.h"

// 全局的wacther观察器 zk server给zkclient的通知
void watchFunc(zhandle_t *zh, int type, int state, const char *path, void *watcherCtx)
{
    if(type==ZOO_SESSION_EVENT) // 回调的消息类型 绘画相关的 连接断开
    {
        if(state==ZOO_CONNECTED_STATE) // 连接成功
        {
            sem_t* sem = (sem_t*)zoo_get_context(zh);
            sem_post(sem);
        }
    }
}
ZkClient::ZkClient()
    : m_zhandle(nullptr)
{
}
ZkClient::~ZkClient()
{
    if (m_zhandle != nullptr)
    {
        zookeeper_close(m_zhandle); // 关闭句柄，释放资源 ，MYSQL_CONN
    }
}
/**
 * zookeeper_mt 多线程版本
 * zookeeper 客户端程序提供了三个线程
 * API 调用线程
 * 网络I/O线程 pthread_create poll
 * wacther回调线程也是一个独立的线程
 */
void ZkClient::Start()
{
    std::string ip = MprpcApplication::GetInstance()->GetConfig().Load("Zookeeperip");
    std::string port = MprpcApplication::GetInstance()->GetConfig().Load("Zookeeperport");
    std::string host = ip + ":" + port;
    m_zhandle = zookeeper_init(host.c_str(), watchFunc, 30000, nullptr, nullptr, 0);
    if (m_zhandle == nullptr)
    {
        std::cout << "zookeeper_init_error!" << std::endl;
        exit(EXIT_FAILURE);
    }

    // 创建一个信号量
    sem_t sem;
    sem_init(&sem, 0, 0);
    // 给指定的句柄添加一些额外的是信息
    zoo_set_context(m_zhandle, &sem);
    // 信号量本质就是一个计数器。0 就是要被阻塞了
    sem_wait(&sem);

    std::cout << "zookeeper_init success!" << std::endl;
}
void ZkClient::Create(const char *path, const char *data, int datalen, int state)
{
    char path_buffer[128];
    int bufferlen = sizeof(path_buffer);
    int flag;
    flag = zoo_exists(m_zhandle, path, 0, nullptr);
    if(ZNONODE == flag)
    {
        flag = zoo_create(m_zhandle, path, data, datalen,&ZOO_OPEN_ACL_UNSAFE, state, path_buffer, bufferlen);
        if(flag==ZOK)
        {
            std::cout<<"znode create success ... path:"<<path<<std::endl;
        }else{
            std::cout<<"flag "<<flag<<std::endl;
            std::cout<<"znode create error ... path:"<<path<<std::endl;
            exit(EXIT_FAILURE);
        }
    }
}
std::string ZkClient::GetData(const char *path)
{
    char buffer[64];
    int bufferlen = sizeof(buffer);
    int flag = zoo_get(m_zhandle,path,0,buffer,&bufferlen,nullptr);
    if(flag!= ZOK)
    {
        std::cout<<"get znode error ..... path:"<<path<<std::endl;
        return "";
    }else{
        return buffer;
    }
}